1 package edu.jiangxin.apktoolbox.reverse; 2 3 import edu.jiangxin.apktoolbox.swing.extend.plugin.PluginPanel; 4 import edu.jiangxin.apktoolbox.swing.extend.listener.SelectDirectoryListener; 5 import edu.jiangxin.apktoolbox.swing.extend.listener.SelectFileListener; 6 import edu.jiangxin.apktoolbox.utils.Constants; 7 import edu.jiangxin.apktoolbox.utils.Utils; 8 import org.apache.commons.io.FilenameUtils; 9 10 import javax.swing.*; 11 import javax.swing.filechooser.FileFilter; 12 import java.awt.*; 13 import java.awt.event.ActionEvent; 14 import java.awt.event.ActionListener; 15 import java.io.File; 16 17 public class ApktoolPanel extends PluginPanel { 18 public ApktoolPanel() throws HeadlessException { 19 super(); 20 } 21 22 @Override 23 public String getPluginFilename() { 24 return "apktool_2.9.2.jar"; 25 } 26 27 @Override 28 public void initUI() { 29 BoxLayout boxLayout = new BoxLayout(this, BoxLayout.Y_AXIS); 30 setLayout(boxLayout); 31 32 JTabbedPane categoryTabbedPane = new JTabbedPane(); 33 add(categoryTabbedPane); 34 35 JPanel decodeCategoryPanel = new ApktoolDecodePanel(); 36 JPanel rebuildCategoryPanel = new ApktoolRebuildPanel(); 37 38 categoryTabbedPane.addTab("Decode", null, decodeCategoryPanel, "Decode the APK file"); 39 categoryTabbedPane.setSelectedIndex(0); 40 categoryTabbedPane.addTab("Rebuild", null, rebuildCategoryPanel, "Rebuild the APK file"); 41 } 42 43 abstract class ApktoolPanelBase extends JPanel { 44 protected JPanel srcPanel; 45 46 protected JPanel targetPanel; 47 48 protected JPanel optionPanel; 49 50 protected JPanel operationPanel; 51 52 protected ApktoolPanelBase() throws HeadlessException { 53 super(); 54 initUI(); 55 } 56 57 private void initUI() { 58 BoxLayout boxLayout = new BoxLayout(this, BoxLayout.Y_AXIS); 59 setLayout(boxLayout); 60 61 createSrcPanel(); 62 add(srcPanel); 63 add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER)); 64 65 createTargetPanel(); 66 add(targetPanel); 67 add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER)); 68 69 createOptionPanel(); 70 add(optionPanel); 71 add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER)); 72 73 createOperationPanel(); 74 add(operationPanel); 75 } 76 77 protected void createSrcPanel() { 78 srcPanel = new JPanel(); 79 srcPanel.setLayout(new BoxLayout(srcPanel, BoxLayout.X_AXIS)); 80 } 81 82 protected void createTargetPanel() { 83 targetPanel = new JPanel(); 84 targetPanel.setLayout(new BoxLayout(targetPanel, BoxLayout.X_AXIS)); 85 } 86 87 protected void createOptionPanel() { 88 optionPanel = new JPanel(); 89 optionPanel.setLayout(new BoxLayout(optionPanel, BoxLayout.X_AXIS)); 90 } 91 92 protected void createOperationPanel() { 93 operationPanel = new JPanel(); 94 operationPanel.setLayout(new BoxLayout(operationPanel, BoxLayout.X_AXIS)); 95 } 96 } 97 98 class ApktoolDecodePanel extends ApktoolPanelBase { 99 private JTextField srcTextField; 100 101 private JTextField targetTextField; 102 103 private JCheckBox resourceIgnoreCheckBox; 104 105 private JCheckBox overrideCheckBox; 106 107 public ApktoolDecodePanel() throws HeadlessException { 108 super(); 109 } 110 111 @Override 112 public void createSrcPanel() { 113 super.createSrcPanel(); 114 115 srcTextField = new JTextField(); 116 srcTextField.setText(conf.getString("apktool.decode.src.file")); 117 118 JButton srcButton = new JButton(bundle.getString("choose.file.button")); 119 srcButton.addActionListener(new SelectFileListener("select a file", srcTextField)); 120 121 srcPanel.add(srcTextField); 122 srcPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER)); 123 srcPanel.add(srcButton); 124 } 125 126 @Override 127 public void createTargetPanel() { 128 super.createTargetPanel(); 129 130 targetTextField = new JTextField(); 131 targetTextField.setText(conf.getString("apktool.decode.target.dir")); 132 133 JButton targetButton = new JButton(bundle.getString("save.dir.button")); 134 targetButton.addActionListener(new SelectDirectoryListener("Save To", targetTextField)); 135 136 targetPanel.add(targetTextField); 137 targetPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER)); 138 targetPanel.add(targetButton); 139 } 140 141 @Override 142 public void createOptionPanel() { 143 super.createOptionPanel(); 144 145 resourceIgnoreCheckBox = new JCheckBox("Ignore res"); 146 resourceIgnoreCheckBox.setSelected(false); 147 optionPanel.add(resourceIgnoreCheckBox); 148 149 overrideCheckBox = new JCheckBox("Override"); 150 overrideCheckBox.setSelected(true); 151 optionPanel.add(overrideCheckBox); 152 } 153 154 @Override 155 public void createOperationPanel() { 156 super.createOperationPanel(); 157 158 JButton decodeButton = new JButton("Decode"); 159 decodeButton.addActionListener(new ApktoolDecodePanel.DecodeButtonActionListener()); 160 161 operationPanel.add(decodeButton); 162 } 163 164 private final class DecodeButtonActionListener implements ActionListener { 165 @Override 166 public void actionPerformed(ActionEvent e) { 167 String srcPath = checkAndGetFileContent(srcTextField, "apktool.decode.src.file", "Source file is invalid"); 168 if (srcPath == null) { 169 return; 170 } 171 172 String targetPath = checkAndGetDirContent(targetTextField, "apktool.decode.target.dir", "Target directory is invalid"); 173 if (targetPath == null) { 174 return; 175 } 176 177 String srcBaseName = FilenameUtils.getBaseName(srcPath); 178 StringBuilder sb = new StringBuilder(); 179 sb.append(ApktoolPanel.this.getPluginStartupCmd()).append(" d ") 180 .append(srcPath).append(" -o ").append(targetPath).append(File.separator).append(srcBaseName); 181 if (resourceIgnoreCheckBox.isSelected()) { 182 sb.append(" -r"); 183 } 184 if (overrideCheckBox.isSelected()) { 185 sb.append(" -f"); 186 } 187 Utils.blockedExecutor(sb.toString()); 188 } 189 } 190 } 191 192 class ApktoolRebuildPanel extends ApktoolPanelBase { 193 private JTextField srcTextField; 194 195 private JTextField targetTextField; 196 197 private JCheckBox signAPK; 198 199 public ApktoolRebuildPanel() throws HeadlessException { 200 super(); 201 } 202 203 @Override 204 public void createSrcPanel() { 205 super.createSrcPanel(); 206 207 srcTextField = new JTextField(); 208 srcTextField.setText(conf.getString("apktool.rebuild.src.dir")); 209 210 JButton srcButton = new JButton(bundle.getString("choose.dir.button")); 211 srcButton.addActionListener(new SelectDirectoryListener("Select Directory", srcTextField)); 212 213 srcPanel.add(srcTextField); 214 srcPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER)); 215 srcPanel.add(srcButton); 216 } 217 218 @Override 219 public void createTargetPanel() { 220 super.createTargetPanel(); 221 222 targetTextField = new JTextField(); 223 targetTextField.setText(conf.getString("apktool.rebuild.target.file")); 224 225 JButton targetButton = new JButton(bundle.getString("save.file.button")); 226 targetButton.addActionListener(new SelectFileListener("save to", targetTextField, new ApktoolRebuildPanel.ApkFileFilter())); 227 228 targetPanel.add(targetTextField); 229 targetPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER)); 230 targetPanel.add(targetButton); 231 } 232 233 @Override 234 public void createOptionPanel() { 235 super.createOptionPanel(); 236 237 signAPK = new JCheckBox("sign APK"); 238 signAPK.setSelected(false); 239 optionPanel.add(signAPK); 240 } 241 242 @Override 243 public void createOperationPanel() { 244 super.createOperationPanel(); 245 246 JButton rebuildButton = new JButton("Rebuild"); 247 rebuildButton.addActionListener(new ApktoolRebuildPanel.RebuildButtonActionListener()); 248 operationPanel.add(rebuildButton); 249 } 250 251 private final class RebuildButtonActionListener implements ActionListener { 252 @Override 253 public void actionPerformed(ActionEvent e) { 254 String srcPath = checkAndGetDirContent(srcTextField, "apktool.rebuild.src.dir", "Source directory is invalid"); 255 if (srcPath == null) { 256 return; 257 } 258 259 String targetPath = checkAndGetNewFileContent(targetTextField, "apktool.rebuild.target.file", "Target file is invalid"); 260 if (targetPath == null) { 261 return; 262 } 263 264 StringBuilder sb = new StringBuilder(); 265 sb.append(ApktoolPanel.this.getPluginStartupCmd()).append(" b ") 266 .append(srcPath).append(" -o ").append(targetPath); 267 Utils.blockedExecutor(sb.toString()); 268 if (signAPK.isSelected()) { 269 sb = new StringBuilder(); 270 sb.append(ApktoolPanel.this.getPluginStartupCmd()) 271 .append(" -keystore ").append(Utils.getToolsPath()).append(File.separator) 272 .append("debug.keystore").append(" -alias androiddebugkey -pswd android ") 273 .append(targetPath); 274 Utils.blockedExecutor(sb.toString()); 275 } 276 } 277 } 278 279 private final class ApkFileFilter extends FileFilter { 280 281 @Override 282 public boolean accept(File f) { 283 String nameString = f.getName(); 284 return nameString.toLowerCase().endsWith(".apk"); 285 } 286 287 @Override 288 public String getDescription() { 289 return "*.apk"; 290 } 291 } 292 } 293 } 294